package com.example.sppmode.DeviceConnectMgr;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;


import com.example.sppmode.Common.Utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.UUID;


public class SppConnMgr {
    private static final String TAG = "SPP-CTRL";

    public static final UUID SPP_UUID = UUID.fromString("50444E53-0000-1000-8000-00805F9B34FB");

    public static final int SPP_DISCONNECTED = 0;
    public static final int SPP_CONNECTED = 1;

    private Context mContext;
    private BluetoothAdapter mBluetoothAdapter = null;
    private RecvThread mRecvThread = null;
    private BluetoothSocket bluetoothSocket = null;
    private InputStream sppInputStream = null;
    private OutputStream sppOutputStream = null;
    private SPPEventListener sppCommListener = null;
    private BluetoothDevice bluetoothDevice = null;
    private FoundDeviceReceiver mFondDevieReceiver = null;

    public SppConnMgr(Context context, SPPEventListener listener) {
        mContext = context;
        sppCommListener = listener;

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        listenBlueState();
    }

    public void connectDevice(String addr) {
        if(addr == null)
            return;

        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(addr);
        if(device == null)
            return;

        if (bluetoothDevice != null && device.getAddress().equals(bluetoothDevice.getAddress())) {
            if (bluetoothSocket != null && bluetoothSocket.isConnected()) {
                updateConnStatus(SPP_CONNECTED);
                return;
            }
        }

        bluetoothDevice = device;
        new Thread(new ConnectRunnable(mContext, device)).start();
    }

    public int sendData(byte[] data, int dataLen) {
        Log.d(TAG, "sendData dataLen=" + dataLen + ", data.length=" + data.length);
        Log.d(TAG, "sendData data=" + Utils.convertByteArray2HexStr(data, dataLen));

        if (bSppSending) {
            Log.d(TAG, "sendData Busy !!!");
            return 1;
        } else {
            bSppSending = true;
            new Thread(new SendRunnable(bluetoothSocket, data, dataLen)).start();
            return 0;
        }
    }

    private class ConnectRunnable implements Runnable {
        Context context;
        BluetoothDevice device = null;

        public ConnectRunnable(Context context, BluetoothDevice device) {
            this.device = device;
            this.device = device;
        }

        @SuppressLint("MissingPermission")
        @Override
        public void run() {
            Log.d(TAG, "SendRunnable run");

            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
                // 等待连接，会阻塞线程
                bluetoothSocket.connect();
                Log.d(TAG, "Spp connected");
                createRecvThread();
                updateConnStatus(SPP_CONNECTED);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private boolean bSppSending = false;

    private class SendRunnable implements Runnable {
        BluetoothSocket bluetoothSocket = null;
        OutputStream outputStream = null;
        byte[] data;
        int dataLen = 0;

        public SendRunnable(BluetoothSocket bluetoothSocket, byte[] data, int dataLen) {
            this.bluetoothSocket = bluetoothSocket;
            this.data = data;
            this.dataLen = dataLen;
        }

        @Override
        public void run() {
            Log.d(TAG, "SendRunnable run");
            if (bluetoothSocket != null && bluetoothSocket.isConnected()) {
                try {
                    outputStream = bluetoothSocket.getOutputStream();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                updateConnStatus(SPP_DISCONNECTED);
                resetData();
            }

            if (outputStream != null) {
                if (data != null && dataLen <= data.length) {
                    try {
                        outputStream.write(data, 0, dataLen);
                    } catch (IOException e) {
                        e.printStackTrace();
                        updateConnStatus(SPP_DISCONNECTED);
                        resetData();
                    } finally {
                        bSppSending = false;
                        data = null;
                        dataLen = 0;
                    }
                }
            }
        }
    }

    private class RecvThread extends Thread {
        Context context;
        BluetoothSocket bluetoothSocket = null;
        InputStream inputStream;
        boolean bThreadRunning = false;
        byte[] recvData = new byte[1024+100];

        public RecvThread(Context context, BluetoothSocket bluetoothSocket) {
            this.context = context;
            this.bluetoothSocket = bluetoothSocket;
        }

        public void exit() {
            bThreadRunning = false;
            Log.d(TAG, "RecvRunnable exit()");
        }

        @Override
        public synchronized void start() {
            super.start();
            bThreadRunning = true;
        }

        @Override
        public void run() {
            while (bThreadRunning) {
                if (bluetoothSocket != null && bluetoothSocket.isConnected()) {
                    try {
                        inputStream = bluetoothSocket.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    updateConnStatus(SPP_DISCONNECTED);
                    bThreadRunning = false;
                    break;
                }

                if (inputStream != null) {
                    try {
                        int readCnt = inputStream.read(recvData);
                        if (readCnt == recvData.length) {
                            Log.d(TAG, "RecvRunnable has more data");
                        } else {
                            Log.d(TAG, "RecvRunnable readCnt=" + readCnt);
                            if (sppCommListener != null) {
                                sppCommListener.onRecvData(recvData, readCnt);
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        updateConnStatus(SPP_DISCONNECTED);
                        resetData();
                    } finally {

                    }
                }

                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    void createRecvThread() {
        mRecvThread = new RecvThread(mContext, bluetoothSocket);
        mRecvThread.start();
    }

    void updateConnStatus(int status) {
        if (sppCommListener != null) {
            sppCommListener.onConnStatusChanged(status);
        }
    }

    void resetData() {

        if (mRecvThread != null)
            mRecvThread.exit();

        if (bluetoothSocket != null) {
            try {

                sppInputStream = null;
                sppOutputStream = null;

                if (bluetoothSocket.getInputStream() != null) {
                    bluetoothSocket.getInputStream().close();
                }

                if (bluetoothSocket.getOutputStream() != null) {
                    bluetoothSocket.getOutputStream().close();
                }

                bluetoothSocket.close();
                bluetoothSocket = null;

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void destory() {
        resetData();
        mContext.unregisterReceiver(mFondDevieReceiver );
    }

    @SuppressLint("MissingPermission")
    private void requestProfileConnectionState() {
        //检测连接状态：
        int a2dp = mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
        int gatt = mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT);
        int sap = mBluetoothAdapter.getProfileConnectionState(BluetoothProfile.SAP);
        //据是否有连接获取已连接的设备
        int flag = -1;
        if (a2dp == BluetoothProfile.STATE_CONNECTED) {
            flag = a2dp;
        } else if (gatt == BluetoothProfile.STATE_CONNECTED) {
            flag = gatt;
        } else if (sap == BluetoothProfile.STATE_CONNECTED) {
            flag = sap;
        }
        if (flag != -1) {
            ProxyListener mProxyListener = new ProxyListener();
            mBluetoothAdapter.getProfileProxy(mContext, mProxyListener, flag);
        }
    }


    private void listenBlueState() {
        //检查当前是否存在蓝牙连接
        requestProfileConnectionState();
        if (mFondDevieReceiver == null) {

            mFondDevieReceiver = new FoundDeviceReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
            mContext.registerReceiver(mFondDevieReceiver, intentFilter);
        }
    }

    private class ProxyListener implements BluetoothProfile.ServiceListener {

        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            Log.d(TAG, "onServiceConnected");
            if (proxy != null) {
                List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                if (mDevices.size() > 0) {
//                    for (int i = 0; i < mDevices.size(); i++) {
//                        //获取BluetoothDevice
//                        BluetoothDevice mDevice = mDevices.get(0);
//                        Log.d(TAG, "mDevice: " + mDevices.get(0).getAddress());
//                        //调用创建Socket连接
//                        connectDevice(mDevice);
//                    }

                    Log.d(TAG, "onServiceConnected ");
                    //connectDevice(bluetoothDevice);
                }
                mBluetoothAdapter.closeProfileProxy(profile, proxy);
            }
        }

        @Override
        public void onServiceDisconnected(int profile) {
            Log.d(TAG, "onServiceDisconnected");
            resetData();
            updateConnStatus(SPP_DISCONNECTED);
        }
    }


    private class FoundDeviceReceiver extends BroadcastReceiver {

        @SuppressLint("MissingPermission")
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
                int adapterState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, BluetoothAdapter.ERROR);
                if (BluetoothAdapter.STATE_CONNECTED == adapterState) {//连接成功
                    //获取BluetoothDevice
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (device != null) {
                        Log.d(TAG, "onReceive STATE_CONNECTED: " + device.getName() + ", " + device.getAddress());

                        //调用创建Socket连接
                        if (bluetoothDevice != null && device.getAddress().equals(bluetoothDevice.getAddress())) {
                            Log.d(TAG, "onReceive STATE_CONNECTED connectDevice");
                            connectDevice(device.getAddress());
                        }
                    }

                } else if (BluetoothAdapter.STATE_CONNECTING == adapterState) {//正在连接
                    Log.d(TAG, "onReceive STATE_CONNECTING");

                } else if (BluetoothAdapter.STATE_DISCONNECTING == adapterState) {//正在连接
                    Log.d(TAG, "onReceive STATE_DISCONNECTING");

                } else if (BluetoothAdapter.STATE_DISCONNECTED == adapterState) {//取消连接
                    Log.d(TAG, "onReceive STATE_DISCONNECTED");
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    if (device != null) {
                        Log.d(TAG, "onReceive STATE_DISCONNECTED: " + device.getName() + ", " + device.getAddress());

                        if (bluetoothDevice != null && device.getAddress().equals(bluetoothDevice.getAddress())) {
                            Log.d(TAG, "onReceive STATE_CONNECTED connectDevice");
                            resetData();
                            updateConnStatus(SPP_DISCONNECTED);
                        }
                    }
                }
            }
        }
    }
}
